package de.uni_potsdam.hpi.bpt.ai.diagram;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * @author Philipp
 * Represents a Stencilset of a shape
 */
public class StencilSet {
	protected String url = null;
	protected String namespace = null;
	protected JSONObject specification = null;
	protected Map<String, JSONObject> stencils = null;
		
	public StencilSet(String namespace, JSONObject specification) {
		this(null, namespace);
		this.specification = specification;
		this.stencils = new HashMap<String, JSONObject>();
		
		try {
			JSONArray stencils = this.specification.getJSONArray("stencils");
			for (int i=0; i<stencils.length(); i++) {
				JSONObject stencil = stencils.getJSONObject(i);
				
				this.stencils.put(stencil.getString("id"), stencil);
			}
		}
		catch(JSONException e) {
			e.printStackTrace();
			this.specification = null;
		}
	}
	
	/** Constructs a stencilSet with url and namespace
	 * @param url
	 * @param namespace
	 */
	public StencilSet(String url, String namespace) {
		this.url = url;
		this.namespace = namespace;
	}
	/** Minimal constructor of an stencilset, only expects an uri
	 * @param namespace
	 */
	public StencilSet(String namespace) {
		this.namespace = namespace;
	}
	
	/** Gice the specific url of an stencilset
	 * @return the url
	 */
	public String getUrl() {
		return url;
	}
	
	/** Set a new specific url for an stencilset
	 * @param url the url to set
	 */
	public void setUrl(String url) {
		this.url = url;
	}
	
	/**Give the namespace of a stencilset
	 * @return the namespace
	 */
	public String getNamespace() {
		return namespace;
	}
	
	/**Set a new namespace for a stencil set
	 * @param namespace the namespace to set
	 */
	public void setNamespace(String namespace) {
		this.namespace = namespace;
	}
	
	public boolean hasSpecification() {
		return null != this.specification;
	}
	
	public boolean isNode(Shape shape) {
		return isNode(shape.getStencilId());
	}

	public boolean isNode(String stencilId) {
		if (null == this.specification) {
			throw new IllegalStateException("StencilSet has no associated specification");
		}
				
		try {
			JSONObject jsonStencil = this.stencils.get(stencilId);
			if (null != jsonStencil && jsonStencil.getString("type").equals("node")) {
				return true;
			}
		} catch (JSONException e) {
			e.printStackTrace();
		}
		
		return false;
	}
	
	/**
	 * Returns a set of all stencil types (StencilType#getId(), Shape#getStencilId()) of the current stencilset.
	 * 
	 * @return
	 */
	public Set<String> getStencils() {
		return this.stencils.keySet();
	}
	
	public JSONObject getSpecification(){
		return this.specification;
	}
	
	public String get(String stencilId, String key) {
		if (null == this.specification) {
			throw new IllegalStateException("StencilSet has no associated specification");
		}

		if (null == key) {
			return null;
		}
		
		JSONObject stencil = this.stencils.get(stencilId);
		if (null != stencil && stencil.has(key)) {
			try {
				return stencil.getString(key);
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		}
		return this.getProperty(stencilId, key);
	}
	
	public String getProperty(String stencilId, String key) {
		
		if (null == this.specification) {
			throw new IllegalStateException("StencilSet has no associated specification");
		}
		
		if (null == key) {
			return null;
		}
		
		JSONObject stencil = this.stencils.get(stencilId);
		if (null != stencil && stencil.has("properties")) {
			try {
				JSONArray properties = stencil.getJSONArray("properties");
				for (int i=0; i<properties.length(); i++) {
					JSONObject prop = properties.getJSONObject(i);
					if (prop.has("id") && key.equals(prop.getString("id")) && prop.has("value")) {
						return prop.getString("value");
					}
				}
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		}
		
		return null;
	}
	
}
